1. Connecting Express Server with Axios (vite)

Now in the previous chapter we created a backend with the json data 4.Setting up Backend

so now we create a normal vite project and in app.js we write a code to get the json data from the backend to display on the webpage

"use client"
import { useEffect, useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
import axios from 'axios'

function App() {
  const [jokes, setjokes] = useState([]);

  useEffect(() => {
    axios.get('http://localhost:3000/jokes')
      .then((response) => {
        setjokes(response.data)
      })
      .catch((error) => {
        console.log(error)
      })
  })

  return (
    <>
      <h1> Jokes page </h1>

      <p>{jokes.length}</p>

      {
        jokes.map((joke, index) => {
          <div key={joke.id}>
            <h3>{joke.title}</h3>
            <p>{joke.cotent}</p>
          </div>
        })
      }
    </>
  )
}
export default App
Note

we used axios for the fetching the data from backend it is a normal package to get data to learn more read this note 5. Theory Axios Read Only

But when we run this front end code we get this error

Access to XMLHttpRequest at 'http://localhost:3000/jokes' from origin 'http://localhost:5173' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

This error means the server at http://localhost:3000 is not allowing requests from the origin http://localhost:5173 due to CORS (Cross-Origin Resource Sharing) restrictions, as it lacks the Access-Control-Allow-Origin header.

What is CORS?

CORS (Cross-Origin Resource Sharing) is a security feature implemented by web browsers that:

Example Scenario

A web page hosted on http://localhost:3000 (frontend) tries to fetch data from http://localhost:5000 (backend). The browser will:

  1. Check if the backend server allows requests from the frontend origin
  2. Block the request if proper CORS headers are not present

Implementation Guide

1. Installation

Install required packages using npm:

npm i dotenv cors express

2. Backend Setup (Using Express)

server.js

// Using ES Modules
import express from 'express';
import dotenv from 'dotenv';
import cors from 'cors';

// Alternative using Common JS:
// const express = require("express")
// const dotenv = require("dotenv").config();
// const cors = require("cors");

const app = express();
dotenv.config();
const port = process.env.PORT;

// Enable CORS for all routes
app.use(cors());

// Routes
app.get("/", (req, res) => {
    res.send("hello");
});

app.get("/api/jokes", (req, res) => {
    const jokes = [
        {
            id: 1,
            title: "1st Joke",
            content: "Why don't skeletons fight each other? They don't have the guts."
        },
        {
            id: 2,
            title: "2nd Joke",
            content: "Why don’t some couples go to the gym? Because some relationships don’t work out."
        },
        {
            id: 3,
            title: "3rd Joke",
            content: "Why did the scarecrow win an award? Because he was outstanding in his field."
        },
        {
            id: 4,
            title: "4th Joke",
            content: "I told my wife she was drawing her eyebrows too high. She looked surprised."
        },
        {
            id: 5,
            title: "5th Joke",
            content: "I’m reading a book about anti-gravity. It’s impossible to put down."
        }
    ];
    res.send(jokes);
});

// Start server
app.listen(port, () => {
    console.log(`Port is running on ${port}`);
});

3. dotenv

  1. .env files let you store sensitive information (like API keys, database passwords, configuration settings) separate from your code, helping keep your secrets secure and making it easier to manage different settings between development and production environments.

  2. The dotenv package loads these environment variables from your .env file into process.env in your Node.js application, making them accessible throughout your code without exposing them in your repository.

    Create a .env file in your backend project folder

    PORT = 3000
    

4. Frontend

App.js

import React, {useState, useEffect} from 'react';
import axios from 'axios';

function App(){
  const [data, setData] = useState([]);
  const [error, setError] = useState(null);

  useEffect(()=>{
    axios.get('/api/jokes')
    .then((response) => {
      setData(response.data)
      
    })
    .catch((err) => {
      setError(err);
      console.log(err);
    })
  },[])

  //as this is asynchronous it will take time to fetch data from api so we run it in another useEffect so whenver the date comes/update it fill fetch directly and print in the console
  useEffect(()=>{
    console.log(data)
  }, [data])



  return (
    <div>
      <ul>
        {data.map((joke)=> (
          <li key={joke.id}> 
          <p>Title: {joke.title}</p>
          <p>Content: {joke.content}</p>
          </li>
        ))}
      </ul>
    </div>
  )
}

export default App;

5. Frontend Proxy Setup

In Vite, proxying is used to handle requests that are made to a different server or backend during development. When you're building a full-stack application, typically you will have your frontend (React app) running on one server (e.g., Vite's development server on localhost:5173) and your backend (e.g., an Express API) running on another server (e.g., localhost:3000).

Why We Use Proxy in Vite:

  1. Cross-Origin Resource Sharing (CORS) Issues: When your frontend makes requests to a different port (or domain) than the one it is served on, the browser will block the request due to CORS restrictions. The proxy in the Vite config allows the frontend to make requests to the backend without triggering CORS errors.

  2. Simplify API Calls: Without a proxy, you would need to specify the full URL (http://localhost:3000/api) in all your API requests. With the proxy, you can make requests like /api/..., and Vite will internally forward them to the appropriate backend server (http://localhost:3000/api/...).

vite.config.js

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vite.dev/config/
export default defineConfig({
  server: {
    proxy:{
      '/api': 'http://localhost:3000',
    },
  },
  plugins: [react()],
})